// Go作者版权所有。版权所有。
// 此源代码的使用受BSD样式的约束
// 可以在许可证文件中找到的许可证。

// 该文件实现了测试支持。

package syntax

import (
	"io"
	"regexp"
	"strings"
)

// CommentsDo解析给定的源并为每个源调用提供的处理程序
// 评论或错误。如果提供给处理程序的文本以“/”开头，则为
// 评论文本；否则将显示错误消息。
func CommentsDo(src io.Reader, handler func(line, col uint, text string)) {
	var s scanner
	s.init(src, handler, comments)
	for s.tok != _EOF {
		s.next()
	}
}

// 错误注释必须以文本“ERROR”msg`或“ERROR msg”开头。
// 忽略“msg”或msg周围的空格。
var errRx = regexp.MustCompile(`^ *ERROR *"?([^"]*)"?`)

// ErrorMap收集带有表单注释文本的所有注释
// `来自给定src的错误“msg”或“ERROR msg”，并返回它们
// as[]错误列在按行号索引的映射中。位置
// 对于每个错误，都是紧靠前一个标记的位置
// 注释、错误消息是从中提取的消息msg
// 注释，并收集同一行上的所有错误
// 在片中，按源顺序。如果没有前面的标记，则
// `错误`注释出现在文件的开头），然后
// 记录的位置未知（行，列=0，0）。如果没有
// 错误注释，结果为零。
func ErrorMap(src io.Reader) (errmap map[uint][]Error) {
	// 前一标记的位置
	var base *PosBase
	var prev struct{ line, col uint }

	var s scanner
	s.init(src, func(_, _ uint, text string) {
		if text[0] != '/' {
			return // 错误，忽略
		}
		if text[1] == '*' {
			text = text[:len(text)-2] // 带材拖尾*/
		}
		if s := errRx.FindStringSubmatch(text[2:]); len(s) == 2 {
			pos := MakePos(base, prev.line, prev.col)
			err := Error{pos, strings.TrimSpace(s[1])}
			if errmap == nil {
				errmap = make(map[uint][]Error)
			}
			errmap[prev.line] = append(errmap[prev.line], err)
		}
	}, comments)

	for s.tok != _EOF {
		s.next()
		if s.tok == _Semi && s.lit != "semicolon" {
			continue // 忽略自动插入的分号
		}
		prev.line, prev.col = s.line, s.col
	}

	return
}
